-module(slotselector).
-export([start/6]).

start(DataSource, Synchro, Port, InterfaceIP, MultiCastIP, ClientClass) ->
	SlotPID = self(),
	SendeProzessPID = spawn(fun() -> sender:start(DataSource, Synchro, SlotPID, Port, InterfaceIP, MultiCastIP, ClientClass) end),
	calc_Sending(SendeProzessPID, 0, 0, 0, [], false).

calc_Sending(SendeProzessPID, SlotUsed, NextFreeSlot, CurrentFrame, TakenSlots, DetectCollision) ->
	receive
		{Slot, FrameNr, ReservedSlot} ->
			NewSlotList = [{Slot,ReservedSlot} | TakenSlots],
			case CurrentFrame < FrameNr of
				true ->
					calc_Sending(SendeProzessPID, SlotUsed, calc_Slot([{Slot,ReservedSlot}]), FrameNr, [{Slot,ReservedSlot}], DetectCollision);
				false when NextFreeSlot == ReservedSlot ->
					calc_Sending(SendeProzessPID, SlotUsed, calc_Slot(NewSlotList), CurrentFrame, NewSlotList, DetectCollision);
				false -> 
					calc_Sending(SendeProzessPID, SlotUsed, NextFreeSlot, CurrentFrame, NewSlotList, DetectCollision)
			end;
		{collision, CollisionSlot} ->
			case SlotUsed == CollisionSlot of 
				true when DetectCollision -> 
					NextFree = calc_Slot(TakenSlots),
					SendeProzessPID ! {collisiondetected, NextFree},
					calc_Sending(SendeProzessPID, SlotUsed, NextFree, CurrentFrame, TakenSlots, false);
				false -> 
					calc_Sending(SendeProzessPID, SlotUsed, NextFreeSlot, CurrentFrame, TakenSlots, DetectCollision);
        true -> 
          calc_Sending(SendeProzessPID, SlotUsed, NextFreeSlot, CurrentFrame, TakenSlots, DetectCollision)
			end;
		getnextfreeslot ->
      random:seed(now()),
			SendeProzessPID ! {nextfreeslot, NextFreeSlot},
			calc_Sending(SendeProzessPID, SlotUsed, NextFreeSlot, CurrentFrame, TakenSlots, DetectCollision);
		{sending, SlotNr} ->
			calc_Sending(SendeProzessPID, SlotNr, NextFreeSlot, CurrentFrame, TakenSlots, true)
	end.

contains(_, []) -> false;
contains(Elem, [Head | Tail]) ->
	case Elem == Head of
		true -> true;
		false -> contains(Elem, Tail)
	end.

calc_Slot(TakenSlots) ->
	calc_Slot2(lists:map(fun({_,Reserved}) -> Reserved end,
			   lists:filter(fun({Slot,_}) -> length(proplists:get_all_values(Slot, TakenSlots)) == 1 end,
			   TakenSlots))).


calc_Slot2(TakenSlots) when length(TakenSlots) >= 25 ->
	random:uniform(25)-1; %%Wenn alle Slots belegt sind, dann einen zufälligen wählen, auch wenn das zu einer Kollision führt

calc_Slot2(TakenSlots) ->
Random = random:uniform(25)-1,
Contains = contains(Random, TakenSlots),
if 
	Contains ->
		calc_Slot2(TakenSlots);
	true ->
		Random
end.